package com.nchu.student_score.service.impl;

import com.nchu.student_score.dataObject.GradeResult;
import com.nchu.student_score.dataObject.StatisticsResult;
import com.nchu.student_score.mapper.GradeMapper;
import com.nchu.student_score.mapper.StudentMapper;
import com.nchu.student_score.mapper.TeachTaskMapper;
import com.nchu.student_score.mapper.TermMapper;
import com.nchu.student_score.model.Grade;
import com.nchu.student_score.model.TeachTask;
import com.nchu.student_score.model.Term;
import com.nchu.student_score.service.StatisticsService;
import com.nchu.student_score.vo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.*;

@Service
public class StatisticsServiceImpl implements StatisticsService {
    @Autowired
    StudentMapper studentMapper;
    @Autowired
    GradeMapper gradeMapper;
    @Autowired
    TeachTaskMapper taskMapper;
    @Autowired
    TermMapper termMapper;

    @Override
    public ResultVo<StatisticsResult> getStuStatistics(GradeResult input) {//获取学生的成绩统计信息
        ResultVo<StatisticsResult> resultVo = new ResultVo<>();//待返回的对象
        StatisticsResult statistics = new StatisticsResult();//待返回的数据

        if(input == null || input.getStuId() == null){//确认学号和学生
            resultVo.setStatus(1);
            resultVo.setMessage("未获得学号!");
        }

        List<GradeResult> gradeResultList = gradeMapper.getGradesList(input);//查出所有成绩记录
        int total = gradeResultList.size();//已完成课程总数

        if(gradeResultList.size() == 0){//没有已完成课程
            resultVo.setStatus(2);
            resultVo.setMessage("您没有已完成的课程!");
            resultVo.setObj(statistics);
            return resultVo;
        }

        int passed = 0,failed = 0,excellenceCount = 0;//合格、不合格、优秀计数
        Map<Integer,List<Double>> map1 = new HashMap<>();//学期平均成绩 一个学期对应一组数据
        Map<Integer,List<Double>> map2 = new HashMap<>();//学期平均排名 一个学期对应一组数据
        for(GradeResult gr : gradeResultList){//对每一个成绩进行遍历并计算
            TeachTask teachTask = taskMapper.selectByPrimaryKey(gr.getTeachId());//查出该成绩对应的教学安排
            //统计总合格数、不合格数、优秀数量
            if(gr.getScore() >= teachTask.getPassingScore()){//判断成绩是否合格
                passed++;
                if(gr.getScore() >= (teachTask.getFullScore() * 0.85))//判断成绩是否优秀
                    excellenceCount++;//成绩优秀计数
            }
            else{//成绩不合格
                failed++;
            }

            List<Grade> gradeList = gradeMapper.selectByTeachId(gr.getTeachId());//查询出该安排下的所有人成绩
            int overCount = 0;//超过的人数
            for(Grade g : gradeList){//计算一门成绩超过的人数
                if(gr.getScore() >= g.getScore())
                    overCount++;
            }

            if(map1.get(teachTask.getTermId()) == null){//避免空指针
                List<Double> list1 = new ArrayList<>();
                List<Double> list2 = new ArrayList<>();
                map1.put(teachTask.getTermId(),list1);
                map2.put(teachTask.getTermId(),list2);
            }

            //在对应学期下记录该门课程的成绩，折算为满分1.00
            map1.get(teachTask.getTermId()).add(gr.getScore() * 1.0 / teachTask.getFullScore());
            //在对应学期下记录平均排名，即超过学生的比例，最大1.00
            map2.get(teachTask.getTermId()).add(overCount * 1.0 / gradeList.size());
        }

        //初始化学期id
        Integer[] termIds = new Integer[map1.size()];
        int termPosition = 0;

        for(Integer id : map1.keySet()){//获取写入学期id
            termIds[termPosition] = id;
            termPosition++;
        }

        double totalScore = 0.0,totalRank = 0.0;//总成绩/总排名
        Arrays.sort(termIds);//对学期id排序，避免出现学期不按时间顺序
        List<Term> terms = termMapper.selectAll();//查询获取全部学期对象
        Map<Integer,Term> termMap = new HashMap<>();//降低当学期数较多时的时间复杂度
        for(Term t : terms){//将学期对象存入map
            termMap.put(t.getTermId(),t);
        }

        //学期对象、学期平均成绩、学期平均排名
        List<Term> termList = new ArrayList<>();
        List<Double> termAvgScore = new ArrayList<>();
        List<Double> termAvgRank = new ArrayList<>();

        for (Integer termId : termIds) {//按照学期id遍历
            int count = 0;//一个学期内计数
            List<Double> list1 = map1.get(termId);//获取一个学期内的成绩
            List<Double> list2 = map2.get(termId);//获取一个学期内的排名
            double termScore = 0.0,termRank = 0.0;//学期内成绩/学期内排名
            for(Double d : list1){
                totalScore += d;//记录总平均分
                termScore += d;//记录学期内平均分
                count++;//学期内完成的成绩计数
            }
            for(Double d : list2){
                totalRank += d;//记录总平均排名
                termRank += d;//记录学期内排名
            }
            //存入学期对象
            termList.add(termMap.get(termId));
            //计算并存入该学期的平均成绩，将成绩由满分1.00转为100.00%(保留两位小数)
            double score= Double.parseDouble(new DecimalFormat("#.00").format(termScore*100.0/count));
            termAvgScore.add(score);
            //计算并存入该学期超过的学生比例，由1.00转为100.00%(保留两位小数)
            double rank = Double.parseDouble(new DecimalFormat("#.00").format(termRank*100.0/count));
            termAvgRank.add(rank);
        }

        //计算及格率
        double passPct = Double.parseDouble(new DecimalFormat("#.00").format(passed*100.0/total));
        //计算优秀率
        double e = excellenceCount * 100.0 / total;
        double excellence = Double.parseDouble(new DecimalFormat("#.00").format(e));
        //计算总平均成绩
        double t = totalScore * 100.0 / total;
        double avgScore = Double.parseDouble(new DecimalFormat("#.00").format(t));
        //计算总平均超过人数
        double avgRank = Double.parseDouble(new DecimalFormat("#.00").format(totalRank*100.0/total));

        //将所有数据set
        statistics.setTotal(total);
        statistics.setPassed(passed);
        statistics.setFailed(failed);
        statistics.setPassPct(passPct);
        statistics.setExcellence(excellence);
        statistics.setAvgScore(avgScore);
        statistics.setAvgRank(avgRank);
        statistics.setTermList(termList);
        statistics.setTermAvgScore(termAvgScore);
        statistics.setTermAvgRank(termAvgRank);

        resultVo.setStatus(0);
        resultVo.setObj(statistics);
        return resultVo;
    }
}
